#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include "protol.hpp"
#define NUM 1024
class Funtion
{
public:
    // 设置非阻塞
    void Setftl(int sock)
    {
        int fl = fcntl(sock, F_GETFL);
        if (fl < 0)
            std::cout << "fcntl fail:" << strerror(errno) << std::endl;
        fcntl(sock, F_SETFL, fl | O_NONBLOCK);
    }
    // 设置端口复用
    void SetPort(int sock)
    {
        int opt = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
    }
    // 处理事件
    void handle(int n, epoll_event *event, int servesock, std::unordered_map<int, Data *> &map)
    {
        for (int i = 0; i < n; i++)
        {
            if (map.find(event[i].data.fd) == map.end())
            {
                std::cout << "map.find fail..." << std::endl;
                break;
            }
            if (event[i].events & EPOLLIN)
                Recv(event[i].data.fd, servesock, map);
            if (event[i].events & EPOLLOUT)
                Write(event[i].data.fd, map);
        }
    }
    // 读事件
    void Recv(int sock, int servesock, std::unordered_map<int, Data *> &map)
    {
        auto cur = map.find(sock);
        if (sock == servesock)
        {
            int arrsock = cur->second->_sptr->Accept();
            if (arrsock < 0)
            {
                std::cout << "arrsock fail.." << std::endl;
                return;
            }
            Setftl(arrsock);
            cur->second->_epfd->Ctl(EPOLL_CTL_ADD, arrsock, EPOLLIN | EPOLLET);
            Data *ptr = new Data(cur->second->_epfd);
            map.emplace(std::make_pair(arrsock, ptr));
            std::cout << "succed and arrsock:" << arrsock << std::endl;
            return;
        }
        while (true)
        {
            char buffer[NUM];
            memset(buffer, 0, NUM);
            ssize_t s = recv(sock, buffer, NUM - 1, 0);
            if (s > 0)
            {
                buffer[s] = '\0';
                cur->second->_inbuffer += buffer;
                std::cout << cur->second->_inbuffer.c_str() << std::endl;
            }
            else if (s == 0)
            {
                std::cout << "对端关闭连接" << sock << std::endl;
                cur->second->_epfd->Ctl(EPOLL_CTL_DEL, sock, 0);
                map.erase(cur);
                delete cur->second;
                close(sock);
                break;
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    std::cout << "缓冲区没有数据" << std::endl;
                    _cut.cut(cur->second->_inbuffer, cur->second->_outbuffer);
                    cur->second->_epfd->Ctl(EPOLL_CTL_MOD, sock, EPOLLIN | EPOLLET | EPOLLOUT);
                    break;
                }
                else if (errno == EINTR)
                {
                    std::cout << "被唤醒" << std::endl;
                    continue;
                }
                else
                {
                    std::cout << "recv fail..." << std::endl;
                    break;
                }
            }
        }
    }
    // 写事件
    void Write(int sock, std::unordered_map<int, Data *> &map)
    {
        auto cur = map.find(sock);
        while (true)
        {
            ssize_t s = send(sock, cur->second->_outbuffer.c_str(), cur->second->_outbuffer.size(), 0);
            if (s > 0)
            {
                cur->second->_outbuffer.clear();
                std::cout << "发送成功" << std::endl;
                cur->second->_epfd->Ctl(EPOLL_CTL_MOD, sock, EPOLLET | EPOLLIN);
            }
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    std::cout << "缓冲区已满或是没数据" << std::endl;
                    break;
                }
                else if (errno == EINTR)
                {
                    std::cout << "被唤醒" << std::endl;
                    continue;
                }
                else
                {
                    std::cout << "send fail..." << std::endl;
                    break;
                }
            }
        }
    }

private:
    Cut _cut;
};